import logging
import uuid
import datetime
module_logger = logging.getLogger('SP.models.server')

## Game info ##

db.define_table('game_info',
    Field('game_name', type='string', requires=(IS_NOT_EMPTY())),
    Field('maxlevels', type='integer', requires=(IS_NOT_EMPTY())),
    Field('levelupcount', type='integer', requires=(IS_NOT_EMPTY())))

if db(db.game_info).count() == 0:
    db.game_info.insert(game_name='quiz', maxlevels=6, levelupcount=3)
    db.game_info.insert(game_name='memory', maxlevels=6, levelupcount=3)

## Specific game info ##

db.define_table('quiz_conf',
    Field('level',type='integer', requires=(IS_NOT_EMPTY())),
    Field('answers',type='integer', requires=(IS_NOT_EMPTY())))

if db(db.quiz_conf).count() == 0:
    db.quiz_conf.insert(level=1, answers=2) # level 1 = 2 answers
    db.quiz_conf.insert(level=2, answers=2) # level 2 = 2 answers
    db.quiz_conf.insert(level=3, answers=4) # level 3 = 4 answers
    db.quiz_conf.insert(level=4, answers=4) # level 4 = 4 answers
    db.quiz_conf.insert(level=5, answers=4) # level 5 = 4 answers
    db.quiz_conf.insert(level=6, answers=4) # level 6 = 4 answers

db.define_table('memory_conf',
    Field('level',type='integer', requires=(IS_NOT_EMPTY())),
    Field('cards',type='integer', requires=(IS_NOT_EMPTY())))

if db(db.memory_conf).count() == 0:
    db.memory_conf.insert(level=1, cards=6)  # level 1 = 2 answers
    db.memory_conf.insert(level=2, cards=8)  # level 2 = 2 answers
    db.memory_conf.insert(level=3, cards=12) # level 3 = 4 answers
    db.memory_conf.insert(level=4, cards=16) # level 4 = 4 answers
    db.memory_conf.insert(level=5, cards=20) # level 5 = 4 answers
    db.memory_conf.insert(level=6, cards=24) # level 6 = 4 answers

## Session stuff ##

db.define_table('session',
    Field('username', type='string', requires=(IS_NOT_EMPTY())),
    Field('password', type='string', requires=(IS_NOT_EMPTY())),
    Field('level', type='integer', requires=(IS_NOT_EMPTY()), default=1),
    Field('start_time', type='datetime', default=request.now),
    Field('end_time', type='datetime', default=None),
    Field('is_closed', type='boolean', default=False))

db.define_table('level_time',
    Field('session_id', type='string', requires=(IS_NOT_EMPTY())),
    Field('start_time', type='string', requires=(IS_NOT_EMPTY())),
    Field('end_time', type='string', default=''))

## Logging ##

db.define_table('rpc_call',
    Field('username', type='string', requires=(IS_NOT_EMPTY())),
    Field('session', type=db.session, requires=(IS_NOT_EMPTY())),
    Field('call', type='string', requires=(IS_NOT_EMPTY())),
    Field('parameters', type='list:string', default=None),
    Field('return_value', type='string', default=None),
    Field('date', type='string', default=request.now))

def _get_session_id():
    """NOT USED AT THE MOMENT"""
    username = auth.user['username']
    password = auth.user['password']
    
    session_id = 0
    count = 0
    
    while 1:
        session_id = str(uuid.uuid4())
        count = db((db.session.username==username) & (db.session.password==password)
                  & (db.session.id==session_id)).count()
        if count <= 0:
            break
        
    module_logger.debug("Get unique session ID: %s" % session_id)
    log_rpc_call(session_id, "_get_session_id", return_value=session_id)
    return session_id

def _open_and_return_session():
    username = auth.user['username']
    password = auth.user['password']
    
    row = db.session.insert(username=username, password=password)
    session_id = row.id
    
    module_logger.debug("Opened new session for the client.")
    log_rpc_call(session_id, "_open_sesion")
    return session_id
    
def _close_session(session_id):
    username = auth.user['username']
    password = auth.user['password']
    
    db((db.session.username==username) & (db.session.password==password)
              & (db.session.id==session_id)).update(end_time=request.now, is_closed=True)
    
    module_logger.debug("Closed current session.")
    param = ['session_id:%s' % session_id]
    log_rpc_call(session_id, "_close_session", parameters=param)
    
def _get_levelupcount(session_id, game_name):
    row = db(db.game_info.game_name==game_name).select(db.game_info.levelupcount).first()
    levelupcount = row['levelupcount']
    module_logger.debug("Get levelupcount: %s" % levelupcount)
    param = ['session_id:%s' % session_id, 'game_name:%s'%game_name]
    log_rpc_call(session_id, "_get_levelupcount", parameters=param, return_value=levelupcount)
    return levelupcount

def _get_levels(session_id, game_name):
    row = db(db.game_info.game_name==game_name).select(db.game_info.maxlevels).first()
    maxlevels = row['maxlevels']
    module_logger.debug("Get amount of playable levels: %s" % maxlevels)
    param = ['session_id:%s' % session_id]
    log_rpc_call(session_id, "_get_levels", parameters=param, return_value=maxlevels)
    return maxlevels

def _get_user(session_id):
    user = auth.user['username']
    module_logger.debug("Get name of user: %s" % user)
    param = ['session_id:%s' % session_id]
    log_rpc_call(session_id, "_get_user", parameters=param, return_value=user)
    return user

def _get_difficulty(session_id):
    username = auth.user['username']
    password = auth.user['password']
    
    row = db((db.session.username==username) & (db.session.password==password)
              & (db.session.id==session_id)).select(db.session.level).first()
    level = row['level']
    
    module_logger.debug("Get level difficulty: %s" % level)
    param = ['session_id:%s' % session_id]
    log_rpc_call(session_id, "_get_difficulty", parameters=param, return_value=level)
    
    return level

def _set_level_end(session_id, game_data):
    module_logger.debug('Core received: %s' % game_data)
    level = game_data['level']
    store_db = game_data['store_db']
    levelup = game_data['levelup']
    score = game_data['score']
     
    if score < 5.0:
        module_logger.debug('score < 5.0 or None, set levelup to false')
        if level > 1:
            module_logger.debug('Decrease level value with one')
            level -= 1
            if level < 1:
                level = 1
        levelup = False
    elif 5 < score < 7:
        module_logger.debug('Set levelup to false')
        levelup = False
    else:
        if level < 6 and levelup:
            module_logger.debug("Increase level with one")
            level += 1
    
    if store_db:
        module_logger.debug("Store score in db: %s" % score)
        
    set_difficulty(session_id, level)
    
    #_save_score(session_id, score)
    param = ['session_id:%s'%session_id,'game_data:%s'%game_data]
    log_rpc_call(session_id, "_set_level_end", parameters=param)

def _set_start_time(session_id):
    cur_time = current_time()
    
    rows = db(db.level_time.session_id==session_id).select()
    
    if not rows:
        db.level_time.insert(session_id=session_id, start_time=cur_time)
    else:
        db((db.level_time.session_id==session_id)).update(start_time=cur_time, end_time='')

    module_logger.debug("Set start_time of current level.")
    param = ['session_id:%s' % session_id]
    log_rpc_call(session_id, "_set_start_time", parameters=param)

def _set_end_time(session_id):
    cur_time = current_time()
    
    db((db.level_time.session_id==session_id)).update(end_time=cur_time)
    
    module_logger.debug("Set end_time of current level.")
    param = ['session_id:%s' % session_id]
    log_rpc_call(session_id, "_set_end_time", parameters=param)

def _calculate_time(session_id):
    """The 'end'time is substracted from 'start'time and the result time is
    returned in a format suitable to put into the dbase.
    Times must be in the format as returnt from util.current_time.
    """
    row = db(db.level_time.session_id==session_id).select().first()
    start = row['start_time']
    end = row['end_time']
    
    start = start.replace('-', ':').replace('_', ':')
    end = end.replace('-', ':').replace('_', ':')
    arg_key0 = [int(s) for s in start.split(':')]
    arg_key1 = [int(s) for s in end.split(':')]
    dt0 = datetime.datetime( * arg_key0)
    dt1 = datetime.datetime( * arg_key1)
    dt2 = dt1 - dt0
    h, m = dt2.seconds / 60, dt2.seconds % 60
    timespend = "%02d:%02d" % (h, m)
    
    module_logger.debug("Calculated timespend for current level.")
    param = ['session_id:%s' % session_id]
    log_rpc_call(session_id, "_calculate_time", parameters=param, return_value=timespend)
    
    return timespend

## Local Methods ##

def _set_difficulty(session_id, level):
    username = auth.user['username']
    password = auth.user['password']
    
    db((db.session.username==username) & (db.session.password==password)
              & (db.session.id==session_id)).update(level=level)
              
    module_logger.debug("Set level difficulty: %s" % level)
    param = ['session_id:%s'%session_id,'level:%s'%level]
    log_rpc_call(session_id, "_set_difficulty", parameters=param, return_value=level)

def log_rpc_call(session_id, call, parameters = None, return_value = None):
    """Logs a given rpc call in the db.
    Parameters: String session_id - unique client session ID
                String call - rpc call (method) name
                List parameters - a list of string containing the parameters and its values
                String return_value - value the call returns"""
    username = auth.user['username']
    
    row = db(db.session.id==session_id).select().first()
    session = row.id
    
    db.rpc_call.insert(username=username, session=session,
                       call=call, parameters=parameters, return_value=return_value)
    